﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Reflection;

namespace DaveSexton.Labs
{
	internal static class Metadata
	{
		public static string GetDisplayName(MemberInfo typeOrMember, string defaultName, params string[] suffixes)
		{
			Contract.Requires(typeOrMember != null);
#if !WINDOWS_PHONE_70
			Contract.Requires(!string.IsNullOrWhiteSpace(defaultName));
			Contract.Requires(suffixes != null);
			Contract.Ensures(!string.IsNullOrWhiteSpace(Contract.Result<string>()));
#else
			Contract.Requires(!string.IsNullOrEmpty(defaultName));
			Contract.Requires(suffixes != null);
			Contract.Ensures(!string.IsNullOrEmpty(Contract.Result<string>()));
#endif

			string name;

			if (!typeOrMember.TryGetDisplayName(out name))
			{
				if (!typeOrMember.TryGetExperiment(out name))
				{
					name = RemoveSuffix(typeOrMember.Name, suffixes);

#if !WINDOWS_PHONE_70
					if (string.IsNullOrWhiteSpace(name))
#else
					if (string.IsNullOrEmpty(name))
#endif
					{
						name = defaultName;
					}
				}
			}

			return name;
		}

		public static string GetDescription(MemberInfo typeOrMember)
		{
			Contract.Requires(typeOrMember != null);
			Contract.Ensures(Contract.Result<string>() != null);

			string description;

			if (!typeOrMember.TryGetDescription(out description))
			{
				description = string.Empty;
			}

			return description;
		}

#if NETFX_CORE
		public static IList<string> GetCategories(TypeInfo type, params string[] suffixes)
#else
		public static IList<string> GetCategories(Type type, params string[] suffixes)
#endif
		{
			Contract.Requires(type != null);
			Contract.Ensures(Contract.Result<IList<string>>() != null);
			Contract.Ensures(Contract.Result<IList<string>>().IsReadOnly);

			string category;

			if (!type.TryGetCategory(out category))
			{
				category = type.Namespace;
			}
			else if (category.Length > 0 && category[0] == '.')
			{
				string prefix = RemoveSuffix(type.Namespace, suffixes);

				if (!string.IsNullOrEmpty(prefix))
				{
					category = prefix + category;
				}
				else
				{
					category = category.Substring(1);
				}
			}

			var list = string.IsNullOrEmpty(category)
				? new List<string>(0)
				: category.Split('.')
									.Select(v => RemoveSuffix(v, suffixes).Trim())
									.Where(v =>
									{
#if !WINDOWS_PHONE_70
										return !string.IsNullOrWhiteSpace(v);
#else
										return !string.IsNullOrEmpty(v);
#endif
									})
									.ToList();

			IList<string> readOnlyList = list.AsReadOnly();

			Contract.Assume(readOnlyList.IsReadOnly);

			return readOnlyList;
		}

		public static string RemoveSuffix(string value, params string[] suffixes)
		{
			Contract.Requires(suffixes != null);
			Contract.Ensures(Contract.Result<string>() != null);

			if (value == null)
			{
				return string.Empty;
			}

			if (suffixes.Length > 0)
			{
				Array.Sort(suffixes, (left, right) => right.Length.CompareTo(left.Length));

				foreach (var suffix in suffixes)
				{
					Contract.Assume(suffix != null);

					if (value.EndsWith(suffix, StringComparison.OrdinalIgnoreCase))
					{
						return value.Substring(0, value.Length - suffix.Length);
					}
				}
			}

			return value;
		}
	}
}